package com.sig.sigandroidDisconnected;

import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;

import com.sig.load.LoadAllElements;
import com.sig.models.Point;
import com.sig.models.Segment;
import com.sig.models.Triangle;
import com.sig.sigandroidDisconnected.DisconnectedActivity.DetectLocation;

public class MyRender implements Renderer {

	List<List<Triangle>> listeTriangle;
	List<List<Segment>> listeSegment;
	LoadAllElements graphics;

	/**
	 * @param for graphics
	 */
	private float ratio;
	private float userScale = 1;
	private float width;
	private float height;
	private float minlat = 47.8380000f;
	private float minlon = 1.9236000f;
	private float maxlat = 47.8508000f;
	private float maxlon = 1.9437000f;
	private float screenwidth = maxlon - minlon;;
	private float screenheigth = maxlat - minlat;
	private float scale;
	private float userDX = 0;
	private float userDY = 0;
	volatile float zoomZ = 0;
	DetectLocation location;
	RepaintMap scaleListener;

	/**
	 * 
	 * @param graphics
	 */
	public MyRender(LoadAllElements graphics, DetectLocation location) {
		super();
		this.graphics = graphics;
		listeTriangle = graphics.getAllTriangles();
		listeSegment = graphics.getAllSegments();
		scaleListener = new RepaintMap();
		this.location = location;
		Log.d("RENDER", "INITIALIZE RENDER");
	}

	@Override
	public synchronized void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrthof(-ratio, ratio, -1, 1, 0, 1);
		gl.glTranslatef(0, 0, -0.00001f);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadIdentity();

		gl.glScalef(200 * userScale, 200 * userScale, 1);

		float cX = (float) (location.getLongitude() - minlon);
		float cY = (float) (location.getLatitude() - minlat);

		float rW = (float) ((ratio * 2) / screenwidth);
		float rH = (float) ((2 / screenheigth));
		float initialScale = (float) Math.max(rW, rH);
		scale = initialScale * userScale;
		gl.glPushMatrix();

		gl.glScalef(200 * userScale, 200 * userScale, 1);
		gl.glTranslatef(-(float) (cX - userDX / 100000f),
				-(float) (cY + userDY / 100000f), 0);
		drawGraphics(gl);
		gl.glPopMatrix();

		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
		Log.d("RENDER", "onDraw");

	}

	private void drawGraphics(GL10 gl) {
		polygonsDrawer(gl, listeTriangle);
		roadsDrawer(gl, listeSegment);
	}

	private void polygonsDrawer(GL10 gl, List<List<Triangle>> alltriangles) {
		synchronized (alltriangles) {
			if (alltriangles != null && !alltriangles.isEmpty()) {
				for (List<Triangle> triangles : alltriangles) {
					triangleDrawer(gl, triangles);
					Log.d("RENDER", "draw polygons");
				}
			}
		}
	}

	private void triangleDrawer(GL10 gl, List<Triangle> triangles) {
		synchronized (triangles) {
			for (Triangle tr : triangles) {
				gl.glVertexPointer(3, GL10.GL_FLOAT, 0, tr.getVertexBuffer());
				// gl.glColorPointer(4, GL10.GL_FLOAT, 0, null);
				gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_SHORT,
						tr.getIndexBuffer());
			}
		}
	}

	private void roadsDrawer(GL10 gl, List<List<Segment>> allroads) {
		synchronized (allroads) {
			if (allroads != null && !allroads.isEmpty()) {
				for (List<Segment> segments : allroads) {
					segmentDrawer(gl, segments);
					Log.d("RENDER", "draw roads");
				}
			}
		}
	}

	private void segmentDrawer(GL10 gl, List<Segment> segments) {
		synchronized (segments) {
			for (Segment s : segments) {
				gl.glPushMatrix();
				Point p = s.getP1();
				gl.glTranslatef((float) p.getX(), (float) p.getY(), 0);
				gl.glRotatef(s.getAngle(), 0, 0, 1);
				gl.glVertexPointer(3, GL10.GL_FLOAT, 0, s.getVertexBuffer());
				gl.glColorPointer(4, GL10.GL_FLOAT, 0, s.getIndexBuffer());
				gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT,
						s.getIndexBuffer());

				gl.glPopMatrix();
			}
		}
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		this.width = width;
		this.height = height;
		gl.glViewport(0, 0, width, height);
		ratio = (float) width / height;
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrthof(-ratio, ratio, -1, 1, 0, 1);

	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
		gl.glClearColor(0.1f, 0.6f, 0.3f, 1);
		gl.glEnable(GL10.GL_DEPTH_TEST);

	}

	public void onDrag(float dX, float dY) {
		userDX += dX;
		userDY += dY;
	}

	/**
	 * Custom scale listener.
	 */
	private class RepaintMap extends SimpleOnScaleGestureListener {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			userScale *= detector.getScaleFactor();
			return true;
		}

	}

	public RepaintMap getScaleListener() {
		return scaleListener;
	}

}
